function DoublyLinkedList() {
  // 属性
  this.head = null // 头部
  this.tail = null // 尾部
  this.length = 0 // 记录链表的长度

  function Node(data) {
    this.prev = null
    this.next = null
    this.data = data
  }

  // 1.向列表末尾添加一个新的项
  DoublyLinkedList.prototype.append = function(data) {
    let newNode = new Node(data)
    if (this.length === 0) {
      this.head = newNode
      this.tail = newNode
    } else {
      this.tail.next = newNode
      newNode.prev = this.tail
      this.tail = newNode
    }
    this.length++
      return this.head
  }

  // 2.向列表特定位置插入一个项
  DoublyLinkedList.prototype.insert = function(position, data) {
    // 判断越界
    if (position < 0 || position > this.length) return false

    let newNode = new Node(data)
    if (position === 0) {
      // 出现在头部
      newNode.next = this.head
      this.head.prev = newNode
      this.head = newNode
    } else if (position === this.length) {
      // 出现在尾部
      newNode.prev = this.tail
      this.tail.next = newNode
      this.tail = newNode
    } else {
      // 出现在中间
      let index = 1
      let crt = this.head // 记录当前结点   -----> 如何提高查找的效率
      while (index++ < position) {
        crt = crt.next
      }
      newNode.next = crt.next
      newNode.prev = crt
      crt.next = newNode
    }
    this.length++
      return this.head
  }

  // 3.获取对应位置的元素
  DoublyLinkedList.prototype.get = function(position) {
    // 判断越界
    if (position <= 0 || position > this.length) return null

    let index = 1
    let crt = this.head // 记录当前结点   -----> 如何提高查找的效率
    while (index++ < position) {
      crt = crt.next
    }
    return crt.data
  }

  // 4.返回元素在链表中的位置，如果不存在就返回-1
  DoublyLinkedList.prototype.indexOf = function(data) {
    let index = 1
    let crt = this.head // 记录当前结点   -----> 如何提高查找的效率
    while (crt.data !== data) {
      crt = crt.next
      if (index === this.length) return -1 // 没找到
      index++
    }
    return index
  }

  // 5.修改某个位置的元素
  DoublyLinkedList.prototype.update = function(position, data) {
    // 判断越界
    if (position <= 0 || position > this.length) return false

    let index = 1
    let crt = this.head // 记录当前结点   -----> 如何提高查找的效率
    while (index++ < position) {
      crt = crt.next
    }
    crt.data = data
    return this.head
  }

  // 6.从链表特定位置移除一项
  DoublyLinkedList.prototype.removeAt = function(position) {
    // 判断越界
    if (position <= 0 || position > this.length) return false

    let index = 1
    let crt = this.head // 记录当前结点   -----> 如何提高查找的效率
    while (index++ < position) {
      crt = crt.next
    }
    let temp = crt.data

    // 在链表头 --->只有一个元素怎么办？
    if (this.length === 1) {
      this.head = null
      this.tail = null
      this.length--
        return temp
    }
    if (crt.prev === null) {
      this.head.next.prev = null
      this.head = this.head.next
    }
    // 在链表尾
    else if (crt.next === null) {
      this.tail.prev.next = null
      this.tail = this.tail.prev
    }
    // 在链表中
    else {
      crt.prev.next = crt.next
      crt.next.prev = crt.prev
    }
    this.length--
      return temp
  }

  // 7.从链表中根据值移除一项，没有值默认移除末尾项
  DoublyLinkedList.prototype.remove = function(data) {
    let index = this.indexOf(data)
    return index > 0 ? this.removeAt(index) : this.removeAt(this.length)
  }

  // 8.判断链表是否为空
  DoublyLinkedList.prototype.isEmpty = function() {
    return this.length === 0
  }

  // 9.返回链表中结点的个数
  DoublyLinkedList.prototype.size = function() {
    return this.length
  }

  // 10.返回链表的字符串展示
  DoublyLinkedList.prototype.toString = function(punctuation) {
    let crt = this.head // 表示当前指向的节点
    let strArr = []
    while (crt) {
      strArr.push(crt.data)
      crt = crt.next
    }
    return strArr.join(punctuation)
  }

  // 11.返回正向正向遍历的结点字符串形式
  DoublyLinkedList.prototype.forwardString = function(punctuation) {
    return this.toString(punctuation)
  }

  // 12.返回反向遍历的字符串形式
  DoublyLinkedList.prototype.backwardString = function(punctuation) {
    let crt = this.tail // 表示当前指向的节点
    let strArr = []
    while (crt) {
      strArr.push(crt.data)
      crt = crt.prev
    }
    return strArr.join(punctuation)
  }
}

module.exports = DoublyLinkedList
let d = new DoublyLinkedList()